package main

import (
	"errors"  // 用于创建自定义错误
	"log"     // 用于日志输出
	"net"     // 用于网络监听和连接处理
	"net/rpc" // 用于实现RPC服务
)

// GetUserReq 定义RPC请求和响应的数据结构
// GetUserReq：客户端发送的查询请求结构，包含要查询的用户ID
type GetUserReq struct {
	Id string `json:"id"` // 用户ID，json标签用于序列化（若使用JSON编解码）
}

// GetUserResp 服务端返回的查询响应结构，包含用户详细信息
type GetUserResp struct {
	Id    string // 用户ID
	Name  string // 用户名
	Phone string // 电话号码
}

// UserServer RPC服务的接收者类型
// 注意：接收者类型必须导出（首字母大写），否则RPC框架无法识别
type UserServer struct{}

// GetUser 远程调用的方法，用于查询用户信息
// 遵循net/rpc远程方法的严格规则：
// 1. 方法接收者类型为*UserServer（导出类型）
// 2. 方法名GetUser（导出，首字母大写）
// 3. 两个参数：第一个为请求（GetUserReq，导出类型），第二个为响应指针（*GetUserResp，导出类型指针）
// 4. 返回值为error类型，用于传递错误信息
func (*UserServer) GetUser(req GetUserReq, resp *GetUserResp) error {
	// 从模拟数据库中查询用户
	if u, ok := users[req.Id]; ok {
		// 若用户存在，通过响应指针返回用户信息
		*resp = GetUserResp{
			Id:    u.Id,
			Name:  u.Name,
			Phone: u.Phone,
		}
		return nil // 无错误，返回nil
	}

	// 若用户不存在，返回自定义错误（会被客户端捕获为rpc.ServerError）
	return errors.New("没有找到用户")
}

func main() {
	// 1. 创建RPC服务实例
	// UserServer是服务接收者，所有导出的符合规则的方法都会被注册为远程方法
	userServer := new(UserServer)

	// 2. 将服务注册到RPC框架中
	// 注册后，服务名默认是接收者的类型名"UserServer"
	// 客户端调用时需使用"UserServer.GetUser"指定服务和方法
	err := rpc.Register(userServer)
	if err != nil {
		log.Fatal("服务注册失败：", err) // 注册失败则退出程序
	}

	// 3. 启动TCP监听，绑定端口1234
	// 网络类型为"tcp"，地址为":1234"（表示监听所有网卡的1234端口）
	listener, err := net.Listen("tcp", ":1234")
	if err != nil {
		log.Fatal("端口监听失败：", err) // 监听失败则退出程序
	}
	defer func(listener net.Listener) {
		err := listener.Close()
		if err != nil {
			log.Println("关闭监听器失败：", err)
		}
	}(listener) // 程序退出时关闭监听器（此处因for循环阻塞，实际需通过信号处理）

	log.Println("RPC服务启动成功，监听端口：1234")

	// 4. 循环接受客户端连接并处理
	// 每接收一个连接，启动一个goroutine处理，实现并发服务
	for {
		// 接受客户端连接（阻塞操作，直到有新连接到来）
		conn, err := listener.Accept()
		if err != nil {
			log.Println("接收客户端连接失败：", err) // 连接失败仅日志记录，不退出循环
			continue
		}

		// 使用goroutine并发处理连接
		// rpc.ServeConn会为该连接创建编解码器（默认gob），并循环处理请求
		go rpc.ServeConn(conn)
	}
}
